import  threading
import time
import copy

class TupleSpace:
    def __init__(self):
        self.tuples = {}
        self.lock = threading.Lock()
        self.stats = {
            'total_ops': 0, 'reads': 0, 'gets': 0, 'puts': 0, 'errors': 0,
            'total_clients': 0, 'start_time': time.time()
        }

    def put(self, key, value):
        with self.lock:
            if key in self.tuples:
                self.stats['errors'] += 1
                return "ERR {} already exists".format(key)
            if len(key) + len(value) > 970:
                self.stats['errors'] += 1
                return "ERR key-value size exceeds limit"
            self.tuples[key] = value
            self.stats['puts'] += 1
            self.stats['total_ops'] += 1
            return "OK ({}, {}) added".format(key, value)

    def get(self, key):
        with self.lock:
            if key not in self.tuples:
                self.stats['errors'] += 1
                self.stats['total_ops'] += 1
                return "ERR {} does not exist".format(key)
            value = self.tuples.pop(key)
            self.stats['gets'] += 1
            self.stats['total_ops'] += 1
            return "OK ({}, {}) removed".format(key, value)

    def read(self, key):
        with self.lock:
            if key not in self.tuples:
                self.stats['errors'] += 1
                self.stats['total_ops'] += 1
                return "ERR {} does not exist".format(key)
            self.stats['reads'] += 1
            self.stats['total_ops'] += 1
            return "OK ({}, {}) read".format(key, self.tuples[key])

    def get_stats(self):
        with self.lock:
            stats = copy.deepcopy(self.stats)
        stats['uptime'] = time.time() - stats['start_time']
        return stats